package com.ruoyi.project.business.utils;

import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.business.common.response.NamesResponse;
import com.ruoyi.project.business.syscity.entity.SysCity;
import com.ruoyi.project.business.syscity.service.ISysCityService;
import com.ruoyi.project.system.entity.SysDept;
import com.ruoyi.project.system.entity.SysUser;
import com.ruoyi.project.system.service.ISysDeptService;
import com.ruoyi.project.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class BusinessUtil {

    public static BigDecimal culByJdk(String expression) {
        // 创建ScriptEngine对象
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        try {
            // 将表达式作为参数传递给eval()函数并获取结果
            Object result = engine.eval(expression);
            log.info("计算结果：" + result);
            return new BigDecimal(result.toString());
        } catch (ScriptException e) {
            log.error("工资计算异常 {}", expression, e);
            throw new CustomException("工资计算异常");
        }
    }

    // Expression 的用法 https://blog.csdn.net/futao__/article/details/134824078
    public static BigDecimal culBySpring(String todo) {
        // 创建ScriptEngine对象
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(todo);
        Object result = expression.getValue();
        log.info("计算结果：" + result);
        return new BigDecimal(result.toString());
    }

    public static void fillListNames(List<? extends NamesResponse> resList, Long tenantId) {
        if(CollectionUtils.isNotEmpty(resList)) {
            List<Long> userIds = resList.stream().map(NamesResponse::getUserId)
                    .filter(tmp -> tmp  != null)
                    .distinct().collect(Collectors.toList());
            ISysUserService userService = SpringUtils.getBean(ISysUserService.class);
            Map<Long, SysUser> userMap = userService.selectUserMapByIds(userIds, tenantId);

            List<Long> deptIds = resList.stream().map(NamesResponse::getDeptId)
                    .filter(tmp -> tmp  != null)
                    .distinct().collect(Collectors.toList());
            ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class);
            Map<Long, SysDept> deptMap = deptService.selectDeptMapByIds(deptIds, tenantId);

            List<String> cityCodes = resList.stream().map(NamesResponse::getCityCode).distinct().collect(Collectors.toList());
            ISysCityService cityService = SpringUtils.getBean(ISysCityService.class);
            Map<String, SysCity> sysCityMap = cityService.selectMapByCityCodes(cityCodes);

            resList.forEach(single -> {
                SysUser sysUser = userMap.get(single.getUserId());
                if(sysUser != null) {
                    single.setNickName(sysUser.getNickName());
                }

                SysDept sysDept = deptMap.get(single.getDeptId());
                if(sysDept != null) {
                    single.setDeptName(sysDept.getDeptName());
                }

                SysCity sysCity = sysCityMap.get(single.getCityCode());
                if(sysCity != null) {
                    single.setCityName(sysCity.getName());
                }
            });

        }
    }

    public static void fillSingleNames(NamesResponse single, Long tenantId) {
        ISysUserService userService = SpringUtils.getBean(ISysUserService.class);
        Map<Long, SysUser> userMap = userService.selectUserMapById(single.getUserId(), tenantId);

        ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class);
        Map<Long, SysDept> deptMap = deptService.selectDeptMapById(single.getDeptId(), tenantId);

        ISysCityService cityService = SpringUtils.getBean(ISysCityService.class);
        Map<String, SysCity> sysCityMap = cityService.selectMapByCityCode(single.getCityCode());


        SysUser sysUser = userMap.get(single.getUserId());
        if(sysUser != null) {
            single.setNickName(sysUser.getNickName());
        }

        SysDept sysDept = deptMap.get(single.getDeptId());
        if(sysDept != null) {
            single.setDeptName(sysDept.getDeptName());
        }

        SysCity sysCity = sysCityMap.get(single.getCityCode());
        if(sysCity != null) {
            single.setCityName(sysCity.getName());
        }

    }

    public static void setFieldName(Object scheule, String fieldName, long value) {
        try {
            Field field = scheule.getClass().getDeclaredField(fieldName);
            // 设置该字段为可访问（如果它是私有的）
            field.setAccessible(true);
            // 使用反射给 dayOfMonth 属性设置值
            field.set(scheule, value);
        } catch (NoSuchFieldException e) {
            log.error("未获取到属性为 {} 的成员变量", fieldName, e);
        } catch (IllegalAccessException e) {
            log.error("为属性为 {} 的成员变量设置值 {} 异常", fieldName, value, e);
        }
    }

    public static Object getFieldValueByName(Object monthSchedule, int dayOfMonth) {
        try {
            Field dayOfMonthField = monthSchedule.getClass().getDeclaredField("dayOfMonth" + dayOfMonth);
            // 设置该字段为可访问（如果它是私有的）
            dayOfMonthField.setAccessible(true);
            // 使用反射给 dayOfMonth 属性设置值
            return dayOfMonthField.get(monthSchedule);
        } catch (NoSuchFieldException e) {
            log.error("未获取到属性为 {} 的成员变量", "dayOfMonth" + dayOfMonth, e);
        } catch (IllegalAccessException e) {
            log.error("读取成员变量 {} 异常", "dayOfMonth" + dayOfMonth, e);
        }
        return null;
    }
}

